#ifndef THREAD_POOL_H_
#define THREAD_POOL_H_

#include<vector>
#include<condition_variable>
#include<future>
#include<memory>
#include"taskqueue.h"
#include"mythread.h"


class ThreadPool
{
private:
    TaskQueue _taskq;               //任务队列
    std::vector<Mythread> _works;   //工作线程
    std::vector<bool> _workstate;  //工作状态

    explicit ThreadPool(int n);              //私有化构造函数
    static ThreadPool* _instance;
public:
    static const int MAXCOUNT=32;
    std::mutex _COND_M;
    std::condition_variable _COND;
    static ThreadPool* GetInstance(int n);  //单例类

    ~ThreadPool();

    int invoke();
    int close();
    inline bool empty();
    inline TaskQueue::Task get_one_task();

    template<class Fn,class... Args>
    auto commit(Fn&& fn,Args&&... args)->std::future<typename std::result_of<Fn(Args...)>::type>;
};

template<class Fn,class... Args>
auto ThreadPool::commit(Fn&&fn,Args&&... args)->std::future<typename std::result_of<Fn(Args...)>::type>
{
    using ResType=typename std::result_of<Fn(Args...)>::type;

    //打包任务函数
    auto task=std::make_shared<std::packaged_task<ResType()>>(
        std::bind(std::forward<Fn>(fn),std::forward<Args>(args)...)
    );

    /*
    由于需要函数 future 所以使用packaged_task
    但function 不能打包packaged_task，所以用lambda进行封装packaged_task,
    但packaged_taks 只支持移动传参，所以使用shared_ptr
    */
    this->_taskq.Enqueue([task](){
        (*task)();
    });

    ThreadPool::_COND.notify_one();

    std::future<ResType> f=task->get_future();
    return f;
}

inline bool ThreadPool::empty()
{
    return _taskq.empty();
}

inline TaskQueue::Task ThreadPool::get_one_task()
{
    return _taskq.Dequeue();
}

#endif
